import { Body, ClassSerializerInterceptor, Controller, Get, NotFoundException, Param, Post, Query, UseInterceptors, UsePipes, ValidationPipe } from "@nestjs/common";
import { UsersService } from "./users.service";
import { User } from "@prisma/client";
import type { UserDto, UserPaginationDto } from "./interfaces/user.dto";
import { ErrorResponse } from "src/common/types/common.type";
import { CreateUserDto } from "src/dtos/uses/users.dto";
import { ApiDescription } from "src/decorators/api-description.decorator";
import { CacheKey, CacheTTL } from "@nestjs/cache-manager";
import { Public } from "src/decorators/is-public.decorator";
import { UserEntity } from "src/dtos/serialization/user.dto";
import { EventEmitter2 } from "@nestjs/event-emitter";

@Controller('users')
export class UsersController {
    constructor(private readonly usersService: UsersService,private eventEmitter: EventEmitter2) { }

    @ApiDescription('Find all users in user controller')
    @Get()
    @CacheKey('allUsers')
    @CacheTTL(10000)
    @Public()
    async findAll(): Promise<UserDto[]> {
        console.log('get user from db.');// ten 10 seconds retrieve data from cache
        return await this.usersService.findAllWithConvert();
    }

    @ApiDescription('Find users with selected fields')
    @Get("/select-fields")
    async findAllSelectFields(): Promise<UserDto[]> {
        return await this.usersService.findAllSelectFields();
    }


    @Public()
    @ApiDescription('Create a new user')
    @Post('/create')
    @UsePipes(new ValidationPipe({ stopAtFirstError:false, whitelist: true }))
    async createUser(@Body() userDto: CreateUserDto): Promise<User | ErrorResponse> {
        const user = await this.usersService.createUser(userDto);
        this.eventEmitter.emit('user.create', user);
        return user;
    }

    @Get("/search-by-query")
    async searchUsers(@Query("query") query: string): Promise<UserDto[]> {
        return await this.usersService.searchUsers(query);
    }

    @Get("/pagination")
    async findUserWithPagination(@Query("pageNum") pageNum = 1, @Query("pageSize") pageSize = 10): Promise<UserPaginationDto> {
        return await this.usersService.findUserWithPagination(pageNum, pageSize);
    }

    @UseInterceptors(ClassSerializerInterceptor) // 序列化用户实体
    @Public()
    @Get('/serialize/:id')
    async serializeUser(@Param('id') id: number): Promise<UserEntity | null> {
        const user = await this.usersService.findUserById(Number(id));
        if (!user) {
            return null;
        }
        return new UserEntity(user);
    }
}
